home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DKBSRC.ARJ / AMIGA.C next >
C/C++ Source or Header  |  1991-05-04  |  21KB  |  682 lines

  1. /*****************************************************************************
  2. *
  3. *                                   amiga.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module handles all of the Amiga-specific code for the raytracer.
  8. *
  9. *
  10. * This software is freely distributable. The source and/or object code may be
  11. * copied or uploaded to communications services so long as this notice remains
  12. * at the top of each file.  If any changes are made to the program, you must
  13. * clearly indicate in the documentation and in the programs startup message
  14. * who it was who made the changes. The documentation should also describe what
  15. * those changes were. This software may not be included in whole or in
  16. * part into any commercial package without the express written consent of the
  17. * author.  It may, however, be included in other public domain or freely
  18. * distributed software so long as the proper credit for the software is given.
  19. *
  20. * This software is provided as is without any guarantees or warranty. Although
  21. * the author has attempted to find and correct any bugs in the software, he
  22. * is not responsible for any damage caused by the use of the software.  The
  23. * author is under no obligation to provide service, corrections, or upgrades
  24. * to this package.
  25. *
  26. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  27. * about them.  Also, if you have any comments or questions, you may contact me
  28. * at the following address:
  29. *
  30. *     David Buck
  31. *     22C Sonnet Cres.
  32. *     Nepean Ontario
  33. *     Canada, K2H 8W7
  34. *
  35. *  I can also be reached on the following bulleton boards:
  36. *
  37. *     OMX              (613) 731-3419
  38. *     Mystic           (613) 596-4249  or  (613) 596-4772
  39. *
  40. *  Fidonet:   1:163/109.9
  41. *  Internet:  dbuck@ccs.carleton.ca
  42. *  The "You Can Call Me RAY" BBS    (708) 358-5611
  43. *
  44. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  45. *
  46. *     The "You Can Call Me RAY" BBS (708) 358-5611
  47. *     The Information Exchange BBS  (708) 945-5575
  48. *
  49. *****************************************************************************/
  50.  
  51. #include "frame.h"
  52. #include "dkbproto.h"
  53.  
  54. #include <proto/exec.h>
  55. #include <proto/intuition.h>
  56. #include <proto/graphics.h>
  57. #include <proto/dos.h>
  58. #include <exec/types.h>
  59. #include <intuition/intuition.h>
  60. #include <graphics/display.h>
  61.  
  62. void geta4(void);
  63. void Requestor_Handler(void);
  64. void Amiga_open(void);
  65. void Amiga_close(void);
  66. void open_requestor(void);
  67. void close_requestor(void);
  68. void write_byte(int x, int y, unsigned char n);
  69. void write_hame_pixel(int x, int y, char Red, char Green, char Blue);
  70.  
  71. void write_cookie(unsigned char *brand, int line);
  72. void make_hame_palette(struct ViewPort *vp);
  73. void SetRGB8 (short reg, unsigned char rr, unsigned char gg,
  74.               unsigned char bb, short base);
  75.  
  76. extern int Options;
  77. extern char DisplayFormat;
  78.  
  79. #define INT_REV 29L
  80. #define GR_REV 29L
  81.  
  82. struct IntuitionBase *IntuitionBase;
  83. struct GfxBase *GfxBase;
  84. struct Screen *s;
  85. volatile struct Window *w;
  86. struct Task *Requestor_Task;
  87.  
  88. volatile int Requestor_Running;
  89. volatile extern int Stop_Flag;
  90.  
  91. #define SCREEN_WIDTH 320
  92. #define SCREEN_HEIGHT 400
  93.  
  94. #define HAME_SCREEN_WIDTH 640
  95. #define HAME_SCREEN_HEIGHT 402
  96.  
  97. struct NewScreen Ham_Screen =
  98.    {
  99.    0, 0,
  100.    SCREEN_WIDTH, SCREEN_HEIGHT,
  101.    6,
  102.    0, 1,
  103.    INTERLACE | HAM,
  104.    SCREENQUIET,
  105.    NULL,
  106.    (UBYTE *) "DKB Ray Trace",
  107.    NULL,
  108.    NULL
  109.    };
  110.  
  111.  
  112. struct NewScreen Ham_E_Screen =
  113.    {
  114.    0, 0,
  115.    HAME_SCREEN_WIDTH, HAME_SCREEN_HEIGHT,
  116.    4,
  117.    0, 1,
  118.    INTERLACE | HIRES,
  119.    SCREENQUIET,
  120.    NULL,
  121.    (UBYTE *) "DKB Ray Trace",
  122.    NULL,
  123.    NULL
  124.    };
  125.  
  126. int lacer; /* if non-zero, screen is an interlace screen. Set this... */
  127.            /* ...as soon as you open your HAM-E screen.               */
  128.  
  129. unsigned char *fp0,*fp1,*fp2,*fp3; /* These are pointers which have been... */
  130.                                    /* ...cached from the screens BitMap[]   */
  131.                                    /* ...array. This allows us to get at    */
  132.                                    /* ...them much faster. Set them as soon */
  133.                                    /* ...as you open your HAM-E screen.     */
  134.  
  135. unsigned char bitpat[] =    /* This table is used as a table of masks... */
  136.   {                         /* ...to isolate bits in the HAM-E pixels    */
  137.     128,64,32,16,8,4,2,1,
  138.   };
  139.  
  140. unsigned char ham_cookie[] =  /* ham mode cookie... preceeds any HAM...    */
  141.   {                           /* ...color registers, and triggers hardware */
  142.     0xA2,0xF5,0x84,0xDC,      /* ...into ham mode.                         */
  143.     0x6D,0xB0,0x7F,0x18
  144.   };
  145.  
  146. struct Window *Requestor_Window;
  147. volatile struct MsgPort *Requestor_Port;
  148.  
  149. struct IntuiText chip Body_Text =
  150.    {0, 1, JAM1, 5, 10, NULL, (UBYTE *) "Click to abort the picture", NULL};
  151.  
  152. struct IntuiText chip Abort_Text =
  153.    {0, 1, JAM1, 5, 3, NULL, (UBYTE *) "Abort", NULL};
  154.  
  155. UWORD chip ColorTbl[16] = { 0x000, 0x111, 0x222, 0x333, 0x444, 0x555, 0x666,
  156.                        0x777, 0x888, 0x999, 0xaaa, 0xbbb, 0xccc, 0xddd,
  157.                        0xeee, 0xfff };
  158.  
  159. LONG last_red = 0, last_green = 0, last_blue = 0, last_y = -1;
  160.  
  161. void amiga_init_dkb_trace(void )
  162.    {
  163.    (void) onbreak(amiga_close_all);
  164.    }
  165.  
  166. int matherr (x)
  167.    struct exception *x;
  168.    {
  169.    printf ("Math error type: %d from function %s values: %g %g\n",
  170.            x->type, x->name, x->arg1, x->arg2);
  171.  
  172.    switch(x->type) 
  173.      {
  174.      case DOMAIN:
  175.      case OVERFLOW:
  176.         x->retval = 1.0e17;
  177.         break;
  178.  
  179.      case SING:
  180.      case UNDERFLOW:
  181.         x->retval = 0.0;
  182.         break;
  183.  
  184.      case TLOSS:
  185.      case PLOSS:
  186.         return (0);
  187.  
  188.      default:
  189.         break;
  190.      }
  191.    return(1);
  192.    }
  193.  
  194. void Requestor_Handler ()
  195.    {
  196.    Requestor_Port = CreatePort ("ray trace port", 0L);
  197.    Requestor_Window = BuildSysRequest
  198.              (NULL, &Body_Text, NULL, &Abort_Text, GADGETUP, 280L, 60L);
  199.    Wait ((1 << Requestor_Port -> mp_SigBit)
  200.           | (1 << Requestor_Window -> UserPort -> mp_SigBit));
  201.  
  202.    Requestor_Running = FALSE;
  203.    Stop_Flag = TRUE;
  204.    }
  205.  
  206. void Amiga_open()
  207.    {
  208.    IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library",INT_REV);
  209.    if (IntuitionBase == NULL)
  210.      exit(FALSE);
  211.  
  212.    GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", GR_REV);
  213.    if (GfxBase == NULL)
  214.      exit(FALSE);
  215.    Requestor_Running = FALSE;
  216.    }
  217.  
  218. void Amiga_close()
  219.    {
  220.    if (Requestor_Running) {
  221.       Signal (Requestor_Task, 1 << Requestor_Port -> mp_SigBit);
  222.       Delay (2L);
  223.       }
  224.  
  225.    if (Requestor_Window)
  226.       FreeSysRequest (Requestor_Window);
  227.  
  228.    Requestor_Window = NULL;
  229.  
  230.    CloseLibrary (GfxBase) ;
  231.    CloseLibrary (IntuitionBase) ;
  232.    }
  233.  
  234. void open_requestor()
  235.    {
  236.    Requestor_Window = NULL;
  237.    Stop_Flag = FALSE;
  238.    Requestor_Running = TRUE;
  239.    Requestor_Task = CreateTask ("Raytrace Requestor", 2L,
  240.                                 (APTR) Requestor_Handler, 20000L);
  241.    }
  242.  
  243. void display_finished ()
  244.    {
  245.    if (Requestor_Running) {
  246.      Signal (Requestor_Task, 1 << Requestor_Port -> mp_SigBit);
  247.      Delay (2L);
  248.      }
  249.  
  250.    if (Requestor_Window)
  251.       FreeSysRequest (Requestor_Window);
  252.  
  253.    Requestor_Window = NULL;
  254.    if (Options & PROMPTEXIT)
  255.       {
  256.       printf ("Finished.\nPress CR to quit.\n");
  257.       getchar();
  258.       }
  259.    }
  260.  
  261. /*:
  262. .n write_byte()
  263. .k low_level write_byte byte_write write_pixel
  264. .b
  265.  
  266. SYNOPSIS:   void write_byte(x,y,n);
  267.                 short x;
  268.                 int y;
  269.                 unsigned char n;
  270.  
  271. FUNCTION:   This function is similar to the Amiga's WritePixel routine.
  272.             is simply takes the incoming position and value and writes
  273.             them to the HAM-E screen appropriately.
  274.  
  275. INPUTS:     x - horizontal position on screen.
  276.             y - vertical position on screen.
  277.             n - value 0-255 to write in the pixel.
  278.  
  279. RESULTS:    None
  280.  
  281. BUGS:       None Known.
  282.  
  283. LIMITATIONS:Hard coded for screen width of 320 pixels (640 hi-res pixels)
  284.  
  285. SEE ALSO:   Global variables "fp3", "fp2", "fp1", "fp0", "bitpat[]"
  286.  
  287. :*/
  288.  
  289. void write_byte(x,y,n)
  290.   int x;
  291.   int y;
  292.   unsigned char n;
  293.   {
  294.   register int ypos,byte_offset;
  295.   register short bit_offset;
  296.     ypos = y * 80; /* index to correct scan line - note hard coded width! */
  297.     bit_offset = (x << 1) & 7; /* find base bit position */
  298.     byte_offset = (x >> 2);   /* find base byte offset */
  299.     if (n & 128) *(fp3 + ypos + byte_offset) |= bitpat[bit_offset];
  300.             else *(fp3 + ypos + byte_offset) &= ~bitpat[bit_offset];
  301.     if (n &  64) *(fp2 + ypos + byte_offset) |= bitpat[bit_offset];
  302.             else *(fp2 + ypos + byte_offset) &= ~bitpat[bit_offset];
  303.     if (n &  32) *(fp1 + ypos + byte_offset) |= bitpat[bit_offset];
  304.             else *(fp1 + ypos + byte_offset) &= ~bitpat[bit_offset];
  305.     if (n &  16) *(fp0 + ypos + byte_offset) |= bitpat[bit_offset];
  306.             else *(fp0 + ypos + byte_offset) &= ~bitpat[bit_offset];
  307.     bit_offset++; /* to next nybble */
  308.     if (bit_offset == 8) /* carry into next byte? */
  309.       {
  310.         bit_offset=0;
  311.         byte_offset++;
  312.       }
  313.     if (n & 8) *(fp3 + ypos + byte_offset) |= bitpat[bit_offset];
  314.           else *(fp3 + ypos + byte_offset) &= ~bitpat[bit_offset];
  315.     if (n & 4) *(fp2 + ypos + byte_offset) |= bitpat[bit_offset];
  316.           else *(fp2 + ypos + byte_offset) &= ~bitpat[bit_offset];
  317.     if (n & 2) *(fp1 + ypos + byte_offset) |= bitpat[bit_offset];
  318.           else *(fp1 + ypos + byte_offset) &= ~bitpat[bit_offset];
  319.     if (n & 1) *(fp0 + ypos + byte_offset) |= bitpat[bit_offset];
  320.           else *(fp0 + ypos + byte_offset) &= ~bitpat[bit_offset];
  321.   }
  322.  
  323. /*:
  324. .n write_cookie()
  325. .k cookie low_level setup configure
  326. .b
  327.  
  328. SYNOPSIS:   void write_cookie(brand,line);
  329.                 unsigned char *brand;
  330.                 int line;
  331.  
  332. FUNCTION:    This function writes the cookie on a particular line.
  333.              The variable "brand" is a pointer to an arrary of data
  334.              that contains the particular cookie for the mode you want.
  335.              These arrays are the global ones "ham_cookie[]" and
  336.              "reg_cookie[]".
  337.              
  338.              Call as:
  339.              
  340.                   write_cookie(ham_cookie,line);
  341.                               -or-
  342.                   write_cookie(reg_cookie,line);
  343.              
  344.              Note: If you have a four line palette, you need to call
  345.              this function for each successive line the palette exists
  346.              upon, for example:
  347.              
  348.                   write_cookie(reg_cookie,0);
  349.                   write_cookie(reg_cookie,1);
  350.                   write_cookie(reg_cookie,2);
  351.                   write_cookie(reg_cookie,3);
  352.                   
  353.                         -or-
  354.                   
  355.                   for (i=0; i<4; i++)
  356.                     {
  357.                       write_cookie(reg_cookie,i);
  358.                     }
  359.              
  360.              If the global variable "lacer" is set, this function will
  361.              write the cookie data on the appropriate lines in both
  362.              fields... sending four lines of cookie to the function
  363.              with the lines 0,1,2,3 will write cookies on line pairs
  364.              0-1, 2-3, 4-5, and 6-7.
  365.  
  366. INPUTS:     A pointer to the apropriate cookie and the line to put it on.
  367.  
  368. RESULTS:    None
  369.  
  370. BUGS:       None Known.
  371.  
  372. LIMITATIONS:None Known.
  373.  
  374. SEE ALSO:   The global variable "lacer" and the "ham_cookie[]"
  375.             and reg_cookie[] global arrays.
  376.  
  377. :*/
  378. void write_cookie(brand,line)
  379.   unsigned char *brand;
  380.   int line;
  381.   {
  382.   int i;
  383.     if (lacer) /* we need double the cookie data! */
  384.       {
  385.         for (i=0; i<8; i++)
  386.           {
  387.             write_byte(i,line*2,brand[i]);
  388.             write_byte(i,(line*2)+1,brand[i]);
  389.           }
  390.       }
  391.     else
  392.       {
  393.         for (i=0; i<8; i++)
  394.           {
  395.             write_byte(i,line,brand[i]);
  396.           }
  397.       }
  398.   }
  399.  
  400. /*:
  401. .n make_hame_palette()
  402. .k amiga_palette palette_amiga setup configure
  403. .b
  404.  
  405. SYNOPSIS:   void make_hame_palette(vp);
  406.                 struct ViewPort *vp;
  407.  
  408. FUNCTION:   Sets palette for Amiga side of hardware: The palette here is
  409.             designed to achieve two independant goals. First, and most
  410.             importantly, it creates a situation where the IRGB lines at
  411.             the Amiga's data port will exactly mirror the data in the
  412.             bitplanes of the screen as each pixel is emitted. 
  413.             Secondly, this palette makes the images visible, if not
  414.             sensible, on a non HAM-e equipped Amiga... Hopefully this
  415.             distinctive color palette will quickly cue the user that
  416.             they are missing something good. :^)
  417.             
  418.             IRGB to 12 bit correspondence:
  419.             
  420.             bit 8 - b3 of red
  421.             bit 4 - b3 of green
  422.             bit 2 - b3 of blue
  423.             bit 1 - b0 of blue
  424.  
  425. INPUTS:     A pointer to the ViewPort that "belongs" to this screen.
  426.  
  427. RESULTS:    None
  428.  
  429. BUGS:       None Known.
  430.  
  431. LIMITATIONS:None Known.
  432.  
  433. SEE ALSO:   
  434.  
  435. :*/
  436. void make_hame_palette(vp)
  437.   struct ViewPort *vp;
  438.   {
  439.   int rr,gg,bb,i;
  440.   int col;
  441.     col=0;
  442.     for (i=0; i<16; i++)
  443.       {
  444.         rr=0; gg=0; bb=0;
  445.         if (i & 8) rr  = 8; /* this builds the IRGB bit outputs...   */
  446.         if (i & 4) gg  = 8; /* ...these four bits are all that are   */
  447.         if (i & 2) bb  = 8; /* ...required to make the HAM-E run,    */
  448.         if (i & 1) bb |= 1; /* ...they xfer b0->b3 to the IRGB lines */
  449.         if (i != 0)     /* we don't mess with c0 - we leave it black */
  450.           {
  451.             rr += (col & 7); /* build strange colors in cregs 1-15...  */
  452.             col += 2;        /* ...these extra bits sent to the color  */
  453.             gg += (col & 7); /* ...registers make amiga palette very   */
  454.             col += 2;        /* ...interesting to look at if the HAM-E */
  455.             bb += (col & 6); /* ...is NOT attached. Otherwise useless. */
  456.             col += 2;        /* ...The code in this "if" is optional.  */
  457.           }
  458.         SetRGB4(vp,i,rr,gg,bb); /* this actually sets the Amiga color regs */
  459.       }
  460.   }
  461.  
  462. /*:
  463. .n SetRGB8()
  464. .k palette_hame hame_palette setup configure
  465. .b
  466.  
  467. SYNOPSIS:   void SetRGB8(reg,rr,gg,bb,base);
  468.                 int reg,rr,gg,bb,base;
  469.  
  470. FUNCTION:   This routine sets the color registers in the HAM-E hardware.
  471.             It can handle color registers located at any point on screen,
  472.             by setting the "base" variable to the starting scan line where
  473.             the color registers exist. Normally, the cookie and it's
  474.             associated color registers are located beginning at scan line 0.
  475.             If the screen is an interlace screen, this routine will set both
  476.             set of color registers identically; when in interlace, the
  477.             HAM-E maintains separate sets of color registers for the
  478.             odd and even interlace fields. Since this routine sets both
  479.             sets of color registers identically, you don't have to
  480.             worry about dealing with this feature.
  481.             
  482. INPUTS:     reg  - the color register number from 0 to 255 to be set
  483.             rr   - the red value from 0-255
  484.             gg   - the green value from 0-255
  485.             bb   - the blue value from 0-255
  486.             base - the starting scan line of the first coookie position
  487.                    (usually zero)
  488.  
  489. RESULTS:    None
  490.  
  491. BUGS:       None Known.
  492.  
  493. LIMITATIONS:None Known.
  494.  
  495. SEE ALSO:   The global variable "lacer"
  496.  
  497. :*/
  498. void SetRGB8(reg,rr,gg,bb,base)
  499.   short reg;
  500.   unsigned char rr,gg,bb;
  501.   short base;
  502.   {
  503.   short p_row,p_index;
  504.     p_row = (reg >> 6) + base;           /* palette row 0-3.  */
  505.     p_index = ((reg & 0x3f) * 3) + 8;    /* reg 0-63 in p_row */
  506.     if (lacer) /* then we need both fields! */
  507.       {
  508.         /* for the even field: */
  509.         write_byte(p_index,   p_row*2, rr);         /* put RED value     */
  510.         write_byte(p_index+1, p_row*2, gg);         /* put GREEN value   */
  511.         write_byte(p_index+2, p_row*2, bb);         /* put BLUE value    */
  512.         
  513.         /* here is the stuff for the ODD field: */
  514.         write_byte(p_index,   (p_row*2)+1, rr);     /* put RED value     */
  515.         write_byte(p_index+1, (p_row*2)+1, gg);     /* put GREEN value   */
  516.         write_byte(p_index+2, (p_row*2)+1, bb);     /* put BLUE value    */
  517.       }
  518.     else /* just write to one field */
  519.       {
  520.         write_byte(p_index,   p_row, rr);     /* put RED value     */
  521.         write_byte(p_index+1, p_row, gg);     /* put GREEN value   */
  522.         write_byte(p_index+2, p_row, bb);     /* put BLUE value    */
  523.       }
  524.   }
  525.  
  526. void display_init (width, height)
  527.    int width, height;
  528.    {
  529.    Amiga_open();
  530.    open_requestor();
  531.  
  532.    Delay (10);
  533.  
  534.    if (DisplayFormat == 'E') {
  535.       if ((s = (struct Screen *) OpenScreen (&Ham_E_Screen)) == NULL)
  536.          exit (FALSE);
  537.       ShowTitle (s, FALSE);
  538.       lacer = 1;
  539.       fp0 = s->BitMap.Planes[0];
  540.       fp1 = s->BitMap.Planes[1];
  541.       fp2 = s->BitMap.Planes[2];
  542.       fp3 = s->BitMap.Planes[3];
  543.       make_hame_palette(&s->ViewPort);
  544.       SetAPen (&(s->RastPort), 0L);
  545.       RectFill (&(s -> RastPort), 0L, 0L, HAME_SCREEN_WIDTH-1, 1);
  546.       SetAPen (&(s->RastPort), 1L);
  547.       RectFill (&(s -> RastPort), 0L, 2L, HAME_SCREEN_WIDTH-1, HAME_SCREEN_HEIGHT-1);
  548.       write_cookie(ham_cookie, 0);
  549.       SetRGB8 (0x11, 0x80, 0x80, 0x80, 0);
  550.       }
  551.    else {
  552.       if ((s = (struct Screen *) OpenScreen (&Ham_Screen)) == NULL)
  553.          exit (FALSE);
  554.  
  555.       ShowTitle (s, FALSE);
  556.  
  557.       LoadRGB4 (&(s->ViewPort), ColorTbl, 16L);
  558.       SetAPen (&(s->RastPort), 7L);
  559.       RectFill (&(s -> RastPort), 0L, 0L, 319L, 399L);
  560.       }
  561.    }
  562.  
  563. void display_close ()
  564.    {
  565.    if (Requestor_Running) {
  566.       Signal (Requestor_Task, 1 << Requestor_Port -> mp_SigBit);
  567.       Delay (2L);
  568.       }
  569.  
  570.    if (Requestor_Window)
  571.       FreeSysRequest (Requestor_Window);
  572.  
  573.    Requestor_Window = NULL;
  574.  
  575.    CloseScreen (s);
  576.    }
  577.  
  578. #define absdif(x,y) ((x > y) ? (x - y) : (y - x))
  579. #define max3(x,y,z) ((x>y)?((x>z)?1:3):((y>z)?2:3))
  580.  
  581. void write_hame_pixel (x, y, Red, Green, Blue)
  582.    int x, y;
  583.    char Red, Green, Blue;
  584.    {
  585.    register unsigned char colour;
  586.    short delta_red, delta_green, delta_blue;
  587.  
  588.    if ((x >= SCREEN_WIDTH )  || (y >= SCREEN_HEIGHT))
  589.       return;
  590.  
  591.    Red = (Red >> 2) & 0x3F;
  592.    Green = (Green >> 2) & 0x3F;
  593.    Blue = (Blue >> 2) & 0x3F;
  594.  
  595.    if (last_y != y) {
  596.       last_y = y;
  597.       last_red = last_green = last_blue = 0;
  598.       }
  599.  
  600.    delta_red = absdif (Red, last_red);
  601.    delta_green = absdif (Green, last_green);
  602.    delta_blue = absdif (Blue, last_blue);
  603.  
  604.    switch (max3(delta_red, delta_green, delta_blue)) {
  605.       case 1:
  606.          last_red = Red;
  607.          colour = 0x80 + Red;
  608.          break;
  609.       case 2:
  610.          last_green = Green;
  611.          colour = 0xc0 + Green;
  612.          break;
  613.       case 3:
  614.          last_blue = Blue;
  615.          colour = 0x40 + Blue;
  616.          break;
  617.       }
  618.  
  619.    write_byte (x, y+2, colour);
  620.    }
  621.  
  622. void display_plot (x, y, Red, Green, Blue)
  623.    int x, y;
  624.    char Red, Green, Blue;
  625.    {
  626.    register short colour, index, mask, i, colour_mask;
  627.    register char *addr;
  628.    short delta_red, delta_green, delta_blue;
  629.  
  630.    if (DisplayFormat == 'E')
  631.       return (write_hame_pixel(x, y, Red, Green, Blue));
  632.  
  633.    if ((x >= SCREEN_WIDTH )  || (y >= SCREEN_HEIGHT))
  634.       return;
  635.  
  636.    Red = (Red >> 4) & 0x0F;
  637.    Green = (Green >> 4) & 0x0F;
  638.    Blue = (Blue >> 4) & 0x0F;
  639.  
  640.    if (last_y != y) {
  641.       last_y = y;
  642.       last_red = last_green = last_blue = 0;
  643.       }
  644.  
  645.    delta_red = absdif (Red, last_red);
  646.    delta_green = absdif (Green, last_green);
  647.    delta_blue = absdif (Blue, last_blue);
  648.  
  649.    switch (max3(delta_red, delta_green, delta_blue)) {
  650.       case 1:
  651.          last_red = Red;
  652.          colour = 0x20 + Red;
  653.          break;
  654.       case 2:
  655.          last_green = Green;
  656.          colour = 0x30 + Green;
  657.          break;
  658.       case 3:
  659.          last_blue = Blue;
  660.          colour = 0x10 + Blue;
  661.          break;
  662.       }
  663.  
  664.    index = (SCREEN_WIDTH >> 3) * y + (x >> 3);
  665.    mask = 0x80 >> (x & 7);
  666.  
  667.    colour_mask = 1;
  668.  
  669.    for (i = 0 ; i < 6 ; i++) {
  670.       addr = &s->BitMap.Planes[i][index];
  671.       *addr &= ~mask;
  672.       *addr |= (colour&colour_mask) ? mask : 0x00;
  673.       colour_mask <<= 1;
  674.       }
  675.    }
  676.  
  677. int amiga_close_all ()
  678.    {
  679.    close_all();
  680.    return (1);
  681.    }
  682.